package com.bt.lms.network.msg;

import com.bt.lms.network.msg.packet.ReqMsgPacket;
import com.bt.lms.utils.Convert;

/**
 * 请求消息
 *
 * @author 朱传博
 */
public class ReqMsg {

    //-----------------常量

    /**
     * 魔数
     */
    public static final String NETWORK_MAGIC_NO = "bot_lms_nine";

    /**
     * 魔数长度
     */
    public static final Byte NETWORK_MAGIC_NO_LEN = 12;

    /**
     * 版本号
     */
    public static final Byte NETWORK_VERSION_ONE = 1;

    /**
     * 序列化算法-json
     */
    public static final Byte NETWORK_SERIAL_COU_JSON = 1;

    /**
     * 事件类型-业务事件
     */
    public static final Byte NETWORK_EVEN_TYPE_BUSINESS = 1;

    /**
     * 业务类型长度
     */
    public static final byte NETWORK_BIZ_TYPE_LEN = 2;

    /**
     * 2way-双向
     */
    public static final byte NETWORK_TWO_WAY_CHAT = 1;

    /**
     * 保留字段长度
     */
    public static final byte NETWORK_REMAIN_FIELD_SIZE = 16;

    /**
     * 请求id长度
     */
    public static final byte NETWORK_REQ_ID_LEN = 8;

    /**
     * 数据长度
     */
    public static final byte NETWORK_DATA_LEN = 4;

    /**
     * 消息头长度
     */
    public static final Integer MSG_HEAD_LENGTH = 46;

    //----------------------字段

    /**
     * 魔数
     */

    private String magicNo = NETWORK_MAGIC_NO;


    /**
     * 协议版本号
     */

    private Byte version = NETWORK_VERSION_ONE;

    /**
     * 序列化算法
     */

    private Byte serialCou = NETWORK_SERIAL_COU_JSON;


    /**
     * 事件类型
     */

    private Byte evenType = NETWORK_EVEN_TYPE_BUSINESS;

    /**
     * 业务类型
     */

    private Short bizType;

    /**
     * 2way
     */

    private Byte twoWay = NETWORK_TWO_WAY_CHAT;

    /**
     * 请求id 毫秒数
     */
    private Long reqId;

    /**
     * 保留字段
     */

    private byte[] remainField = new byte[NETWORK_REMAIN_FIELD_SIZE];


    /**
     * 消息体
     */

    private String data;


    /**
     * 转请求消息包
     *
     * @return 请求消息包
     */
    public ReqMsgPacket toReqMsgPacket() {

        //要返回的对象
        ReqMsgPacket reqMsgPacket = new ReqMsgPacket();

        //1.消息头
        //魔数
        String magicNo = this.getMagicNo();
        byte[] magicNoBytes = magicNo.getBytes();
        reqMsgPacket.setMagicNo(magicNoBytes);
        //协议版本号
        Byte version = this.getVersion();
        reqMsgPacket.setVersion(version);
        //序列化算法
        Byte serialCou = this.getSerialCou();
        reqMsgPacket.setVersion(serialCou);
        //事件类型
        Byte evenType = this.getEvenType();
        reqMsgPacket.setVersion(evenType);
        //业务类型
        Short bizType = this.getBizType();
        byte[] bizTypeBytes = Convert.shortToBytes(bizType);
        reqMsgPacket.setBizType(bizTypeBytes);
        //2Way
        Byte twoWay = this.getTwoWay();
        reqMsgPacket.setTwoWay(twoWay);
        //请求id
        long reqId = System.currentTimeMillis();
        byte[] reqIdBytes = Convert.longToBytes(reqId);
        reqMsgPacket.setReqID(reqIdBytes);
        //保留字段
        byte[] retainField = this.getRemainField();
        reqMsgPacket.setRemainField(retainField);

        //2.消息体 数据
        String data = this.getData();
        byte[] dataBytes = data.getBytes();
        reqMsgPacket.setData(dataBytes);
        //消息头--数据长度
        int dataLen = dataBytes.length;
        byte[] dataLenBytes = Convert.intToBytes(dataLen);
        reqMsgPacket.setDataLen(dataLenBytes);

        return reqMsgPacket;
    }

    /**
     * 字节数组转请求消息
     *
     * @param sumBytes 总字节数组
     * @return 请求消息
     */
    public static ReqMsg toReqMsg(byte[] sumBytes) {
        //要返回的对象
        ReqMsg reqMsg = new ReqMsg();

        //数组拷贝角标
        int index = 0;

        //1.消息头
        //魔数
        byte[] magicNoBytes = new byte[ReqMsg.NETWORK_MAGIC_NO_LEN];
        System.arraycopy(sumBytes, index, magicNoBytes, 0, ReqMsg.NETWORK_MAGIC_NO_LEN);
        index += ReqMsg.NETWORK_MAGIC_NO_LEN;
        String magicNo = new String(magicNoBytes);
        reqMsg.setMagicNo(magicNo);
        //协议版本号
        byte version = sumBytes[index++];
        reqMsg.setVersion(version);
        //序列化算法
        byte serialCou = sumBytes[index++];
        reqMsg.setSerialCou(serialCou);
        //事件类型
        byte evenType = sumBytes[index++];
        reqMsg.setEvenType(evenType);
        //业务类型
        byte[] bizTypeBytes = new byte[ReqMsg.NETWORK_BIZ_TYPE_LEN];
        System.arraycopy(sumBytes, index, bizTypeBytes, 0, ReqMsg.NETWORK_BIZ_TYPE_LEN);
        index += ReqMsg.NETWORK_BIZ_TYPE_LEN;
        short bizType = Convert.bytesToShort(bizTypeBytes);
        reqMsg.setBizType(bizType);
        //2way
        byte twoWay = sumBytes[index++];
        reqMsg.setTwoWay(twoWay);
        //请求id
        byte[] reqIDBytes = new byte[ReqMsg.NETWORK_REQ_ID_LEN];
        System.arraycopy(sumBytes, index, reqIDBytes, 0, ReqMsg.NETWORK_REQ_ID_LEN);
        index += ReqMsg.NETWORK_REQ_ID_LEN;
        Long reqId = Convert.bytesToLong(reqIDBytes);
        reqMsg.setReqId(reqId);
        //保留字段
        byte[] remainFieldBytes = new byte[ReqMsg.NETWORK_REMAIN_FIELD_SIZE];
        System.arraycopy(sumBytes, index, remainFieldBytes, 0, ReqMsg.NETWORK_REMAIN_FIELD_SIZE);
        index += ReqMsg.NETWORK_REMAIN_FIELD_SIZE;
        reqMsg.setRemainField(remainFieldBytes);
        //数据长度
        byte[] dataLenBytes = new byte[ReqMsg.NETWORK_DATA_LEN];
        System.arraycopy(sumBytes, index, dataLenBytes, 0, ReqMsg.NETWORK_DATA_LEN);
        index += ReqMsg.NETWORK_DATA_LEN;
        int dataLen = Convert.bytesToInt(dataLenBytes);

        //消息体
        byte[] dataBytes = new byte[dataLen];
        System.arraycopy(sumBytes, index, dataBytes, 0, dataLen);
        String data = new String(dataBytes);
        reqMsg.setData(data);

        return reqMsg;
    }

    /**
     * 转总数组
     *
     * @return 总数组
     */
    public byte[] toBytes() {

        //数据
        String data = this.getData();
        byte[] dataBytes = data.getBytes();

        //数据长度
        int dataLen = dataBytes.length;

        //要返回的对象 总数组
        byte[] sumBytes = new byte[dataBytes.length + ReqMsg.MSG_HEAD_LENGTH];

        //数组角标
        int index = 0;
        //挨个添进总数组
        //1.消息头
        //魔数
        String magicNo = this.getMagicNo();
        byte[] prepareMagicNoBytes = magicNo.getBytes();
        index = arrayCopy(sumBytes, prepareMagicNoBytes, index);
        //协议版本号
        Byte version = this.getVersion();
        sumBytes[index++] = version;
        //序列化算法
        Byte serialCou = this.getSerialCou();
        sumBytes[index++] = serialCou;
        //事件类型
        Byte evenType = this.getEvenType();
        sumBytes[index++] = evenType;
        //业务类型
        Short bizType = this.getBizType();
        byte[] bizTypeBytes = Convert.shortToBytes(bizType);
        index = arrayCopy(sumBytes, bizTypeBytes, index);
        //2way
        Byte twoWay = this.getTwoWay();
        sumBytes[index++] = twoWay;
        //请求id
        long reqId = System.currentTimeMillis();
        byte[] reqIdBytes = Convert.longToBytes(reqId);
        index = arrayCopy(sumBytes, reqIdBytes, index);
        //保留字段
        byte[] retainField = this.getRemainField();
        index = arrayCopy(sumBytes, retainField, index);
        //数据长度
        byte[] dataLenBytes = Convert.intToBytes(dataLen);
        index = arrayCopy(sumBytes, dataLenBytes, index);

        //2.消息体
        //数据
        arrayCopy(sumBytes, dataBytes, index);

        return sumBytes;
    }

    /**
     * 数组拷贝
     *
     * @param dest  目标数组
     * @param src   源数组
     * @param index 总数组角标
     * @return  更新后的数组角标
     */
    private int arrayCopy(byte[] dest, byte[] src, int index) {

        for (byte b : src) {
            dest[index] = b;
            index++;
        }

        return index;
    }

    public String getMagicNo() {
        return magicNo;
    }

    public void setMagicNo(String magicNo) {
        this.magicNo = magicNo;
    }

    public Byte getVersion() {
        return version;
    }

    public void setVersion(Byte version) {
        this.version = version;
    }

    public Byte getSerialCou() {
        return serialCou;
    }

    public void setSerialCou(Byte serialCou) {
        this.serialCou = serialCou;
    }

    public Byte getEvenType() {
        return evenType;
    }

    public void setEvenType(Byte evenType) {
        this.evenType = evenType;
    }

    public Short getBizType() {
        return bizType;
    }

    public void setBizType(Short bizType) {
        this.bizType = bizType;
    }

    public Byte getTwoWay() {
        return twoWay;
    }

    public void setTwoWay(Byte twoWay) {
        this.twoWay = twoWay;
    }

    public byte[] getRemainField() {
        return remainField;
    }

    public void setRemainField(byte[] remainField) {
        this.remainField = remainField;
    }

    public Long getReqId() {
        return reqId;
    }

    public void setReqId(Long reqId) {
        this.reqId = reqId;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}
